home *** CD-ROM | disk | FTP | other *** search
/ Internet Tools (InfoMagic) / Internet Tools.iso / ip / test / ttcp.c.Z / ttcp.c
C/C++ Source or Header  |  1989-09-04  |  13KB  |  616 lines

  1. /*
  2.  *    T T C P . C
  3.  *
  4.  * Test TCP connection.  Makes a connection on port 2000
  5.  * and transfers zero buffers or data copied from stdin.
  6.  *
  7.  * Usable on 4.2, 4.3, and 4.1a systems by defining one of
  8.  * BSD42 BSD43 (BSD41a)
  9.  *
  10.  * Modified for operation under 4.2BSD, 18 Dec 84
  11.  *      T.C. Slattery, USNA
  12.  * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
  13.  */
  14. #ifndef lint
  15. static char RCSid[] = "@(#)$Header: ttcp.c,v 1.10 87/09/02 23:26:36 mike Exp $ (BRL)";
  16. #endif
  17.  
  18. #define BSD43
  19. /* #define BSD42 */
  20. /* #define BSD41a */
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <netdb.h>
  29. #include <sys/time.h>        /* struct timeval */
  30.  
  31. #ifdef SYSV
  32. #include <sys/times.h>
  33. #include <sys/param.h>
  34. #else
  35. #include <sys/resource.h>
  36. #endif
  37.  
  38. struct sockaddr_in sinme;
  39. struct sockaddr_in sinhim;
  40. struct sockaddr_in sindum;
  41. struct sockaddr_in frominet;
  42.  
  43. int domain, fromlen;
  44. int fd;                /* fd of network socket */
  45.  
  46. int buflen = 1024;        /* length of buffer */
  47. char *buf;            /* ptr to dynamic buffer */
  48. int nbuf = 1024;        /* number of buffers to send in sinkmode */
  49.  
  50. int udp = 0;            /* 0 = tcp, !0 = udp */
  51. int options = 0;        /* socket options */
  52. int one = 1;                    /* for 4.3 BSD style setsockopt() */
  53. short port = 2000;        /* TCP port number */
  54. char *host;            /* ptr to name of host */
  55. int trans;            /* 0=receive, !0=transmit mode */
  56. int sinkmode;            /* 0=normal I/O, !0=sink/source mode */
  57.  
  58. struct hostent *addr;
  59. extern int errno;
  60.  
  61. char Usage[] = "\
  62. Usage: ttcp -t [-options] host <in\n\
  63.     -l##    length of bufs written to network (default 1024)\n\
  64.     -s    source a pattern to network\n\
  65.     -n##    number of bufs written to network (-s only, default 1024)\n\
  66.     -p##    port number to send to (default 2000)\n\
  67.     -u    use UDP instead of TCP\n\
  68. Usage: ttcp -r [-options] >out\n\
  69.     -l##    length of network read buf (default 1024)\n\
  70.     -s    sink (discard) all data from network\n\
  71.     -p##    port number to listen at (default 2000)\n\
  72.     -B    Only output full blocks, as specified in -l## (for TAR)\n\
  73.     -u    use UDP instead of TCP\n\
  74. ";    
  75.  
  76. char stats[128];
  77. double t;            /* transmission time */
  78. long nbytes;            /* bytes on net */
  79. int b_flag = 0;            /* use mread() */
  80.  
  81. void prep_timer();
  82. double read_timer();
  83. double cput, realt;        /* user, real time (seconds) */
  84.  
  85. main(argc,argv)
  86. int argc;
  87. char **argv;
  88. {
  89.     unsigned long addr_tmp;
  90.  
  91.     if (argc < 2) goto usage;
  92.  
  93.     argv++; argc--;
  94.     while( argc>0 && argv[0][0] == '-' )  {
  95.         switch (argv[0][1]) {
  96.  
  97.         case 'B':
  98.             b_flag = 1;
  99.             break;
  100.         case 't':
  101.             trans = 1;
  102.             break;
  103.         case 'r':
  104.             trans = 0;
  105.             break;
  106.         case 'd':
  107.             options |= SO_DEBUG;
  108.             break;
  109.         case 'n':
  110.             nbuf = atoi(&argv[0][2]);
  111.             break;
  112.         case 'l':
  113.             buflen = atoi(&argv[0][2]);
  114.             break;
  115.         case 's':
  116.             sinkmode = 1;    /* source or sink, really */
  117.             break;
  118.         case 'p':
  119.             port = atoi(&argv[0][2]);
  120.             break;
  121.         case 'u':
  122.             udp = 1;
  123.             break;
  124.         default:
  125.             goto usage;
  126.         }
  127.         argv++; argc--;
  128.     }
  129.     if(trans)  {
  130.         /* xmitr */
  131.         if (argc != 1) goto usage;
  132.         bzero((char *)&sinhim, sizeof(sinhim));
  133.         host = argv[0];
  134.         if (atoi(host) > 0 )  {
  135.             /* Numeric */
  136.             sinhim.sin_family = AF_INET;
  137. #ifdef cray
  138.             addr_tmp = inet_addr(host);
  139.             sinhim.sin_addr = addr_tmp;
  140. #else
  141.             sinhim.sin_addr.s_addr = inet_addr(host);
  142. #endif
  143.         } else {
  144.             if ((addr=gethostbyname(host)) == NULL)
  145.                 err("bad hostname");
  146.             sinhim.sin_family = addr->h_addrtype;
  147.             bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
  148. #ifdef cray
  149.             sinhim.sin_addr = addr_tmp;
  150. #else
  151.             sinhim.sin_addr.s_addr = addr_tmp;
  152. #endif cray
  153.         }
  154.         sinhim.sin_port = htons(port);
  155.         sinme.sin_port = 0;        /* free choice */
  156.     } else {
  157.         /* rcvr */
  158.         sinme.sin_port =  htons(port);
  159.     }
  160.  
  161.     if( (buf = (char *)malloc(buflen)) == (char *)NULL)
  162.         err("malloc");
  163.     fprintf(stderr,"ttcp%s: nbuf=%d, buflen=%d, port=%d\n",
  164.         trans?"-t":"-r",
  165.         nbuf, buflen, port);
  166.  
  167.     if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0)
  168.         err("socket");
  169.     mes("socket");
  170.  
  171.     if (bind(fd, &sinme, sizeof(sinme)) < 0)
  172.         err("bind");
  173.  
  174.     if (!udp)  {
  175.         if (trans) {
  176.         /* We are the client if transmitting */
  177.         if(options)  {
  178. #ifdef BSD42
  179.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  180. #else BSD43
  181.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  182. #endif
  183.                 err("setsockopt");
  184.         }
  185.         if(connect(fd, &sinhim, sizeof(sinhim) ) < 0)
  186.             err("connect");
  187.         mes("connect");
  188.         } else {
  189.         /* otherwise, we are the server and 
  190.              * should listen for the connections
  191.              */
  192.         listen(fd,0);   /* allow a queue of 0 */
  193.         if(options)  {
  194. #ifdef BSD42
  195.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  196. #else BSD43
  197.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  198. #endif
  199.                 err("setsockopt");
  200.         }
  201.         fromlen = sizeof(frominet);
  202.         domain = AF_INET;
  203.         if((fd=accept(fd, &frominet, &fromlen) ) < 0)
  204.             err("accept");
  205.         mes("accept");
  206.         }
  207.     }
  208.     prep_timer();
  209.     errno = 0;
  210.     if (sinkmode) {      
  211.         register int cnt;
  212.         if (trans)  {
  213.             pattern( buf, buflen );
  214.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr start */
  215.             while (nbuf-- && Nwrite(fd,buf,buflen) == buflen)
  216.                 nbytes += buflen;
  217.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  218.         } else {
  219.             while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  220.                 static int going = 0;
  221.                 if( cnt <= 4 )  {
  222.                     if( going )
  223.                         break;    /* "EOF" */
  224.                     going = 1;
  225.                     prep_timer();
  226.                 } else
  227.                     nbytes += cnt;
  228.             }
  229.         }
  230.     } else {
  231.         register int cnt;
  232.         if (trans)  {
  233.             while((cnt=read(0,buf,buflen)) > 0 &&
  234.                 Nwrite(fd,buf,cnt) == cnt)
  235.                 nbytes += cnt;
  236.         }  else  {
  237.             while((cnt=Nread(fd,buf,buflen)) > 0 &&
  238.                 write(1,buf,cnt) == cnt)
  239.                 nbytes += cnt;
  240.         }
  241.     }
  242.     if(errno) err("IO");
  243.     (void)read_timer(stats,sizeof(stats));
  244.     if(udp&&trans)  {
  245.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  246.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  247.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  248.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  249.     }
  250.     fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", stats);
  251.     if( cput <= 0.0 )  cput = 0.001;
  252.     if( realt <= 0.0 )  realt = 0.001;
  253.     fprintf(stderr,"ttcp%s: %ld bytes processed\n",
  254.         trans?"-t":"-r", nbytes );
  255.     fprintf(stderr,"ttcp%s: %9g CPU sec  = %9g KB/cpu sec,  %9g Kbits/cpu sec\n",
  256.         trans?"-t":"-r",
  257.         cput,
  258.         ((double)nbytes)/cput/1024,
  259.         ((double)nbytes)*8/cput/1024 );
  260.     fprintf(stderr,"ttcp%s: %9g real sec = %9g KB/real sec, %9g Kbits/sec\n",
  261.         trans?"-t":"-r",
  262.         realt,
  263.         ((double)nbytes)/realt/1024,
  264.         ((double)nbytes)*8/realt/1024 );
  265.     exit(0);
  266.  
  267. usage:
  268.     fprintf(stderr,Usage);
  269.     exit(1);
  270. }
  271.  
  272. err(s)
  273. char *s;
  274. {
  275.     fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
  276.     perror(s);
  277.     fprintf(stderr,"errno=%d\n",errno);
  278.     exit(1);
  279. }
  280.  
  281. mes(s)
  282. char *s;
  283. {
  284.     fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
  285. }
  286.  
  287. pattern( cp, cnt )
  288. register char *cp;
  289. register int cnt;
  290. {
  291.     register char c;
  292.     c = 0;
  293.     while( cnt-- > 0 )  {
  294.         while( !isprint((c&0x7F)) )  c++;
  295.         *cp++ = (c++&0x7F);
  296.     }
  297. }
  298.  
  299. /******* timing *********/
  300.  
  301. #ifdef SYSV
  302. extern long time();
  303. static long time0;
  304. static struct tms tms0;
  305. #else
  306. static struct    timeval time0;    /* Time at which timeing started */
  307. static struct    rusage ru0;    /* Resource utilization at the start */
  308.  
  309. static void prusage();
  310. static void tvadd();
  311. static void tvsub();
  312. static void psecs();
  313. #endif
  314.  
  315. /*
  316.  *            P R E P _ T I M E R
  317.  */
  318. void
  319. prep_timer()
  320. {
  321. #ifdef SYSV
  322.     (void)time(&time0);
  323.     (void)times(&tms0);
  324. #else
  325.     gettimeofday(&time0, (struct timezone *)0);
  326.     getrusage(RUSAGE_SELF, &ru0);
  327. #endif
  328. }
  329.  
  330. /*
  331.  *            R E A D _ T I M E R
  332.  * 
  333.  */
  334. double
  335. read_timer(str,len)
  336. char *str;
  337. {
  338. #ifdef SYSV
  339.     long now;
  340.     struct tms tmsnow;
  341.     char line[132];
  342.  
  343.     (void)time(&now);
  344.     realt = now-time0;
  345.     (void)times(&tmsnow);
  346.     cput = tmsnow.tms_utime - tms0.tms_utime;
  347.     cput /= HZ;
  348.     if( cput < 0.00001 )  cput = 0.01;
  349.     if( realt < 0.00001 )  realt = cput;
  350.     sprintf(line,"%g CPU secs in %g elapsed secs (%g%%)",
  351.         cput, realt,
  352.         cput/realt*100 );
  353.     (void)strncpy( str, line, len );
  354.     return( cput );
  355. #else
  356.     /* BSD */
  357.     struct timeval timedol;
  358.     struct rusage ru1;
  359.     struct timeval td;
  360.     struct timeval tend, tstart;
  361.     char line[132];
  362.  
  363.     getrusage(RUSAGE_SELF, &ru1);
  364.     gettimeofday(&timedol, (struct timezone *)0);
  365.     prusage(&ru0, &ru1, &timedol, &time0, line);
  366.     (void)strncpy( str, line, len );
  367.  
  368.     /* Get real time */
  369.     tvsub( &td, &timedol, &time0 );
  370.     realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
  371.  
  372.     /* Get CPU time (user+sys) */
  373.     tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
  374.     tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
  375.     tvsub( &td, &tend, &tstart );
  376.     cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
  377.     if( cput < 0.00001 )  cput = 0.00001;
  378.     return( cput );
  379. #endif
  380. }
  381.  
  382. #ifndef SYSV
  383. static void
  384. prusage(r0, r1, e, b, outp)
  385.     register struct rusage *r0, *r1;
  386.     struct timeval *e, *b;
  387.     char *outp;
  388. {
  389.     struct timeval tdiff;
  390.     register time_t t;
  391.     register char *cp;
  392.     register int i;
  393.     int ms;
  394.  
  395.     t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
  396.         (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
  397.         (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
  398.         (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
  399.     ms =  (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
  400.  
  401. #define END(x)    {while(*x) x++;}
  402.     cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
  403.     for (; *cp; cp++)  {
  404.         if (*cp != '%')
  405.             *outp++ = *cp;
  406.         else if (cp[1]) switch(*++cp) {
  407.  
  408.         case 'U':
  409.             tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
  410.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  411.             END(outp);
  412.             break;
  413.  
  414.         case 'S':
  415.             tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
  416.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  417.             END(outp);
  418.             break;
  419.  
  420.         case 'E':
  421.             psecs(ms / 100, outp);
  422.             END(outp);
  423.             break;
  424.  
  425.         case 'P':
  426.             sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
  427.             END(outp);
  428.             break;
  429.  
  430.         case 'W':
  431.             i = r1->ru_nswap - r0->ru_nswap;
  432.             sprintf(outp,"%d", i);
  433.             END(outp);
  434.             break;
  435.  
  436.         case 'X':
  437.             sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
  438.             END(outp);
  439.             break;
  440.  
  441.         case 'D':
  442.             sprintf(outp,"%d", t == 0 ? 0 :
  443.                 (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
  444.             END(outp);
  445.             break;
  446.  
  447.         case 'K':
  448.             sprintf(outp,"%d", t == 0 ? 0 :
  449.                 ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
  450.                 (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
  451.             END(outp);
  452.             break;
  453.  
  454.         case 'M':
  455.             sprintf(outp,"%d", r1->ru_maxrss/2);
  456.             END(outp);
  457.             break;
  458.  
  459.         case 'F':
  460.             sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt);
  461.             END(outp);
  462.             break;
  463.  
  464.         case 'R':
  465.             sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt);
  466.             END(outp);
  467.             break;
  468.  
  469.         case 'I':
  470.             sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock);
  471.             END(outp);
  472.             break;
  473.  
  474.         case 'O':
  475.             sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock);
  476.             END(outp);
  477.             break;
  478.         case 'C':
  479.             sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw,
  480.                 r1->ru_nivcsw-r0->ru_nivcsw );
  481.             END(outp);
  482.             break;
  483.         }
  484.     }
  485.     *outp = '\0';
  486. }
  487.  
  488. static void
  489. tvadd(tsum, t0, t1)
  490.     struct timeval *tsum, *t0, *t1;
  491. {
  492.  
  493.     tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  494.     tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  495.     if (tsum->tv_usec > 1000000)
  496.         tsum->tv_sec++, tsum->tv_usec -= 1000000;
  497. }
  498.  
  499. static void
  500. tvsub(tdiff, t1, t0)
  501.     struct timeval *tdiff, *t1, *t0;
  502. {
  503.  
  504.     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  505.     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  506.     if (tdiff->tv_usec < 0)
  507.         tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  508. }
  509.  
  510. static void
  511. psecs(l,cp)
  512. long l;
  513. register char *cp;
  514. {
  515.     register int i;
  516.  
  517.     i = l / 3600;
  518.     if (i) {
  519.         sprintf(cp,"%d:", i);
  520.         END(cp);
  521.         i = l % 3600;
  522.         sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
  523.         END(cp);
  524.     } else {
  525.         i = l;
  526.         sprintf(cp,"%d", i / 60);
  527.         END(cp);
  528.     }
  529.     i %= 60;
  530.     *cp++ = ':';
  531.     sprintf(cp,"%d%d", i / 10, i % 10);
  532. }
  533. #endif
  534.  
  535. /*
  536.  *            N R E A D
  537.  */
  538. Nread( fd, buf, count )
  539. {
  540.     struct sockaddr_in from;
  541.     int len = sizeof(from);
  542.     register int cnt;
  543.     if( udp )  {
  544.         cnt = recvfrom( fd, buf, count, 0, &from, &len );
  545.     } else {
  546.         if( b_flag )
  547.             cnt = mread( fd, buf, count );    /* fill buf */
  548.         else
  549.             cnt = read( fd, buf, count );
  550.     }
  551.     return(cnt);
  552. }
  553.  
  554. /*
  555.  *            N W R I T E
  556.  */
  557. Nwrite( fd, buf, count )
  558. {
  559.     register int cnt;
  560.     if( udp )  {
  561. again:
  562.         cnt = sendto( fd, buf, count, 0, &sinhim, sizeof(sinhim) );
  563.         if( cnt<0 && errno == ENOBUFS )  {
  564.             delay(18000);
  565.             errno = 0;
  566.             goto again;
  567.         }
  568.     } else {
  569.         cnt = write( fd, buf, count );
  570.     }
  571.     return(cnt);
  572. }
  573.  
  574. delay(us)
  575. {
  576.     struct timeval tv;
  577.  
  578.     tv.tv_sec = 0;
  579.     tv.tv_usec = us;
  580.     (void)select( 1, (char *)0, (char *)0, (char *)0, &tv );
  581.     return(1);
  582. }
  583.  
  584. /*
  585.  *            M R E A D
  586.  *
  587.  * This function performs the function of a read(II) but will
  588.  * call read(II) multiple times in order to get the requested
  589.  * number of characters.  This can be necessary because
  590.  * network connections don't deliver data with the same
  591.  * grouping as it is written with.  Written by Robert S. Miles, BRL.
  592.  */
  593. int
  594. mread(fd, bufp, n)
  595. int fd;
  596. register char    *bufp;
  597. unsigned    n;
  598. {
  599.     register unsigned    count = 0;
  600.     register int        nread;
  601.  
  602.     do {
  603.         nread = read(fd, bufp, n-count);
  604.         if(nread < 0)  {
  605.             perror("ttcp_mread");
  606.             return(-1);
  607.         }
  608.         if(nread == 0)
  609.             return((int)count);
  610.         count += (unsigned)nread;
  611.         bufp += nread;
  612.      } while(count < n);
  613.  
  614.     return((int)count);
  615. }
  616.